home *** CD-ROM | disk | FTP | other *** search
/ Merciful 2 / Merciful - Disc 2.iso / software / d / devioustools25.dms / devioustools25.adf / utils / 003.lzx / AMountains / artist.c < prev    next >
C/C++ Source or Header  |  2004-02-13  |  20KB  |  658 lines

  1. /************************************************************************/
  2. /* routines to render a fractal landscape as an image                    */
  3. /************************************************************************/
  4.  
  5. #include <proto/dos.h>
  6.  
  7. #include <m68881.h>
  8. #include <math.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11.  
  12. #include "paint.h"
  13. #include "crinkle.h"
  14. #include "global.h"
  15.  
  16. static Col get_col( Height, Height, Height, Height );
  17. static int project( int, Height );
  18.  
  19.  
  20. #define SIDE 1.0
  21.  
  22. double    vstrength;    // strength of vertical light source
  23. double    lstrength;    // strength of vertical light source
  24. int        base;       // parity flag for mirror routine
  25.  
  26. Parm fold_param;
  27.  
  28. /* -------------------------------------------------------------------- */
  29. /* setup the colour lookup table                                        */
  30. /* -------------------------------------------------------------------- */
  31.  
  32. void set_clut( int max_col, Gun *red, Gun *green, Gun *blue )
  33. {
  34.     int        band, shade;
  35.     double    top, bot;
  36.     double    intensity;
  37.     int        tmp;
  38.  
  39.     /* ---------------------------------------------------------------- */
  40.     /* double rb[N_BANDS] = { 0.167,0.200,0.333,0.450,0.600,1.000 };    */
  41.     /* double gb[N_BANDS] = { 0.667,0.667,0.500,0.500,0.600,1.000 };    */
  42.     /* double bb[N_BANDS] = { 0.500,0.450,0.333,0.200,0.000,1.000 };    */
  43.     /* ---------------------------------------------------------------- */
  44.  
  45.     double rb[N_BANDS];
  46.     double gb[N_BANDS];
  47.     double bb[N_BANDS];
  48.  
  49.     /* ---------------------------------------------------------------- */
  50.     /* band base colours as RGB fractions                                */
  51.     /* ---------------------------------------------------------------- */
  52.  
  53.     rb[0] = 0.450; rb[1] = 0.600; rb[2] = 1.000;
  54.     gb[0] = 0.500; gb[1] = 0.600; gb[2] = 1.000;
  55.     bb[0] = 0.333; bb[1] = 0.000; bb[2] = 1.000;
  56.  
  57.     red[BLACK]           = 0;                    // black
  58.     green[BLACK]         = 0;
  59.     blue[BLACK]          = 0;
  60.  
  61.     red[WHITE]            = COL_RANGE;            // white
  62.     green[WHITE]        = COL_RANGE;
  63.     blue[WHITE]            = COL_RANGE;
  64.  
  65.     red[SKY]            = 0.404 * COL_RANGE;    // sky
  66.     green[SKY]            = 0.588 * COL_RANGE;
  67.     blue[SKY]            = COL_RANGE;
  68.  
  69.     red[SEA_LIT]        = 0;                    // sea (lit)
  70.     green[SEA_LIT]        = 0.500 * COL_RANGE;
  71.     blue[SEA_LIT]        = 0.700 * COL_RANGE;
  72.  
  73.     red[SEA_UNLIT]       = 0;                    // sea (unlit)
  74.     green[SEA_UNLIT]    = ((ambient+(vfract/(1.0+vfract)))*0.500)*COL_RANGE;
  75.     blue[SEA_UNLIT]        = ((ambient+(vfract/(1.0+vfract)))*0.700)*COL_RANGE;
  76.  
  77.     if( MIN_COL > max_col ) {
  78.         PutStr( "set_clut: less than the minimum number of colours available\n" );
  79.         exit( 1 );
  80.     }
  81.  
  82.     /* ---------------------------------------------------------------- */
  83.     /* max_col can over-rule band_size                                    */
  84.     /* ---------------------------------------------------------------- */
  85.  
  86.     while( BAND_BASE + band_size * N_BANDS > max_col ) {
  87.         band_size--;
  88.     }
  89.     
  90.     for ( band = 0; band<N_BANDS; band++ ) {
  91.         for( shade = 0; shade < band_size; shade++ ) {
  92.             if( BAND_BASE + band * band_size + shade >= max_col ) {
  93.                 PutStr( "INTERNAL ERROR, overflowed clut\n" );
  94.                 exit( 1 );
  95.             }
  96.  
  97.             /* -------------------------------------------------------- */
  98.             /* set red                                                    */
  99.             /* -------------------------------------------------------- */
  100.  
  101.             top            = rb[band];
  102.             bot            = ambient * top;
  103.             intensity    = bot + ( shade * ( top - bot ) ) / ( band_size - 1 );
  104.             tmp            = COL_RANGE * intensity;
  105.             if ( tmp < 0 ) {
  106.                 Printf( "set_clut: internal error: invalid code %ld\n", tmp );
  107.                 exit( 2 );
  108.             }
  109.             if( tmp > COL_RANGE ) {
  110.                 tmp = COL_RANGE;
  111.             }
  112.             red[BAND_BASE + band * band_size + shade] = tmp;
  113.  
  114.             /* -------------------------------------------------------- */
  115.             /* set green                                                */
  116.             /* -------------------------------------------------------- */
  117.  
  118.             top            = gb[band];
  119.             bot            = ambient * top;
  120.             intensity    = bot + ( shade * ( top - bot ) ) / ( band_size - 1 );
  121.             tmp            = COL_RANGE * intensity;
  122.             if ( tmp < 0 ) {
  123.                 Printf( "set_clut: internal error: invalid code %ld\n", tmp );
  124.                 exit( 2 );
  125.             }
  126.             if( tmp > COL_RANGE ) {
  127.                 tmp = COL_RANGE;
  128.             }
  129.             green[BAND_BASE + band * band_size + shade] = tmp;
  130.  
  131.             /* -------------------------------------------------------- */
  132.             /* set blue                                                    */
  133.             /* -------------------------------------------------------- */
  134.  
  135.             top            = bb[band];
  136.             bot            = ambient * top;
  137.             intensity    = bot + shade * ( top - bot ) / ( band_size - 1 );
  138.             tmp            = COL_RANGE * intensity;
  139.             if ( tmp < 0 ) {
  140.                 Printf( "set_clut: internal error: invalid code %ld\n", tmp );
  141.                 exit( 2 );
  142.             }
  143.             if( tmp > COL_RANGE ) {
  144.                 tmp = COL_RANGE;
  145.             }
  146.             blue[BAND_BASE + band * band_size + shade] = tmp;
  147.         }
  148.     }
  149. }
  150.  
  151. /* -------------------------------------------------------------------- */
  152. /* extract the table of heights from the Strip struct and discard the    */
  153. /*  rest of the struct.                                                    */
  154. /* -------------------------------------------------------------------- */
  155.  
  156. Height *extract( Strip *s )
  157. {
  158.     int        i;
  159.     Height    *p;
  160.  
  161.     p = s->d;
  162.     free( s );
  163.     for( i = 0; i < width; i++ ) {
  164.         p[i] = shift + vscale * p[i];
  165.     }
  166.     return p;
  167. }
  168.  
  169. /* -------------------------------------------------------------------- */
  170. /* initialise the variables for the artist routines.                    */
  171. /* -------------------------------------------------------------------- */
  172.  
  173. void init_artist_variables( void )
  174. {
  175.     double    dh, dd;
  176.     int        pwidth;        // longest lengthscale for update
  177.  
  178.     width    = ( 1 << levels ) + 1;
  179.     pwidth    = ( 1 << ( levels - stop ) ) + 1;
  180.  
  181.     /* ---------------------------------------------------------------- */
  182.     /* make the fractal SIDE wide, this makes it easy to predict the    */
  183.     /* average height returned by calcalt. If we have stop != 0 then    */
  184.     /* make the largest update length = SIDE                            */
  185.     /* ---------------------------------------------------------------- */
  186.  
  187.     cos_phi    = cos( phi );
  188.     sin_phi    = sin( phi );
  189.     tan_phi    = tan( phi );
  190.  
  191.     x_fact    = cos_phi * cos( alpha );
  192.     y_fact    = cos_phi * sin( alpha );
  193.     vscale    = stretch * pwidth;            // have approx same height as fractal width
  194.                                         // this makes each pixel SIDE=1.0 wide.
  195.                                         // c.f. get_col
  196.     delta_shadow    = tan_phi / cos( alpha );
  197.     shadow_slip        = tan( alpha );
  198.  
  199.     /* ---------------------------------------------------------------- */
  200.     /* guess the average height of the fractal                            */
  201.     /* ---------------------------------------------------------------- */
  202.  
  203.     varience     = vscale * pow( SIDE , 2.0 * fdim );
  204.     shift        *= varience;
  205.     varience    += shift;
  206.  
  207.     start = ( sealevel - shift ) / vscale;    // always start at sealevel
  208.  
  209.     /* ---------------------------------------------------------------- */
  210.     /* set the position of the view point                                */
  211.     /* ---------------------------------------------------------------- */
  212.  
  213.     viewheight    = altitude * width;
  214.     viewpos        = - distance * width;
  215.  
  216.     /* ---------------------------------------------------------------- */
  217.     /* set viewing angle and focal length (vertical-magnification)        */
  218.     /* try mapping the bottom of the fractal to the bottom of the        */
  219.     /* screen. Try to get points in the middle of the fractal            */
  220.     /* to be 1 pixel high                                                */
  221.     /* ---------------------------------------------------------------- */
  222.  
  223.     dh        = viewheight;
  224.     dd        = width / 2.0 - viewpos;
  225.     focal    = sqrt( dd * dd + dh * dh );
  226.  
  227. #ifndef SLOPPY
  228.     tan_vangle    = ( sealevel - viewheight ) / viewpos;
  229.     vangle        = atan ( tan_vangle ) - atan( height / focal / 2.0 ); 
  230. #else
  231.  
  232.     /* ---------------------------------------------------------------- */
  233.     /* we are making some horrible approximations to avoid trig funcs    */
  234.     /* ---------------------------------------------------------------- */
  235.  
  236.     tan_vangle = ( sealevel - viewheight ) / viewpos - height / 2.0 / focal;
  237. #endif
  238.  
  239.     fold_param.mean            = mean;
  240.     fold_param.rg1            = smooth & 4;
  241.     fold_param.rg2            = smooth & 2;
  242.     fold_param.rg3            = smooth & 1;
  243.     fold_param.cross        = cross;
  244.     fold_param.force_front    = slope;
  245.     fold_param.force_back    = 0;
  246.     fold_param.forceval        = forceheight;
  247.     fold_param.mix            = mix;
  248.     fold_param.midmix        = midmix;
  249.     fold_param.fdim            = fdim;
  250.  
  251.     top = make_fold( &fold_param, levels, stop, SIDE / pwidth );
  252.  
  253.     /* ---------------------------------------------------------------- */
  254.     /* use first set of heights to set shadow value                        */
  255.     /* ---------------------------------------------------------------- */
  256.  
  257.     shadow        = extract( next_strip( top ) );
  258.     a_strip        = extract( next_strip( top ) ); 
  259.     b_strip        = extract( next_strip( top ) );
  260.  
  261.     /* ---------------------------------------------------------------- */
  262.     /* initialise the light strengths                                    */
  263.     /* ---------------------------------------------------------------- */
  264.  
  265.     vstrength    = vfract * contrast / ( 1.0 + vfract );
  266.     lstrength    = contrast / ( 1.0 + vfract );
  267. }
  268.  
  269. /* -------------------------------------------------------------------- */
  270. /* calculate the colour of a point.                                        */
  271. /* -------------------------------------------------------------------- */
  272.  
  273. static Col get_col( Height p, Height p_minus_x, Height p_minus_y, Height shadow )
  274. {
  275.     Height    delta_x,
  276.             delta_y,
  277.             delta_x_sqr,
  278.             delta_y_sqr,
  279.             hypot_sqr;
  280.   
  281.     double    norm, dshade;
  282.     Height    effective;
  283.     Col        result;
  284.     int        band, shade;
  285.  
  286.     /* ---------------------------------------------------------------- */
  287.     /* if underwater                                                    */
  288.     /* ---------------------------------------------------------------- */
  289.  
  290.     if ( p < sealevel ) {
  291.         if( shadow > sealevel ) {
  292.             return SEA_UNLIT;
  293.         }
  294.         else {
  295.             return SEA_LIT;
  296.         }
  297.     }
  298.  
  299.     /* ---------------------------------------------------------------- */
  300.     /* We have three light sources, one slanting in from the left one    */
  301.     /* directly from above and an ambient light.                        */
  302.     /* For the directional sources illumination is proportional to the    */
  303.     /* cosine between the normal to the surface and the light.            */
  304.     /*                                                                    */
  305.     /* The surface contains two vectors                                    */
  306.     /*    ( 1, 0, delta_x )                                                */
  307.     /*    ( 0, 1, delta_y )                                                */
  308.     /*                                                                    */
  309.     /* The normal therefore is parallel to                                */
  310.     /*    ( -delta_x, -delta_y, 1 ) / sqrt( 1 + delta_x² + delta_y² )        */
  311.     /*                                                                    */
  312.     /* For light parallel to ( cos_phi, 0, -sin_phi ) the cosine is        */
  313.     /*    ( cos_phi * delta_x + sin_phi ) / sqrt(1 + delta_x² + delta_y²)    */
  314.     /*                                                                    */
  315.     /* For light parallel to                                            */
  316.     /*    ( cos_phi * cos_alpha, cos_phi * sin_alpha, -sin_phi )            */
  317.     /* the cosine is                                                    */
  318.     /* cos_phi * cos_alpha * delta_x + cos_phi * sin_alpha * delta_y + sin_phi    */
  319.     /* -----------------------------------------------------------------------    */
  320.     /*                  sqrt( 1 + delta_x² + delta_y² )                            */
  321.     /*                                                                    */
  322.     /* For vertical light the cosine is                                    */
  323.     /*    1 / sqrt( 1 + delta_x² + delta_y² )                                */
  324.     /* ---------------------------------------------------------------- */
  325.  
  326.     delta_x        = p - p_minus_x;
  327.     delta_y        = p - p_minus_y;
  328.     delta_x_sqr    = delta_x * delta_x;
  329.     delta_y_sqr    = delta_y * delta_y;
  330.     hypot_sqr    = delta_x_sqr + delta_y_sqr;
  331.     norm        = sqrt( 1.0 + hypot_sqr );
  332.  
  333.     /* ---------------------------------------------------------------- */
  334.     /* calculate effective height                                        */
  335.     /* ---------------------------------------------------------------- */
  336.  
  337.     effective = p + varience * contour / ( 1.0 + hypot_sqr );
  338.  
  339.     /* ---------------------------------------------------------------- */
  340.     /* calculate colour band.                                            */
  341.     /* ---------------------------------------------------------------- */
  342.  
  343.     band = ( effective / varience ) * N_BANDS;
  344.     if ( band < 0 ) {
  345.         band = 0;
  346.     }
  347.     if( band > N_BANDS - 1 ) {
  348.         band = N_BANDS - 1;
  349.     }
  350.     result = BAND_BASE + ( band * band_size );
  351.  
  352.     /* ---------------------------------------------------------------- */
  353.     /* calculate the illumination stength                                */
  354.     /*                                                                    */
  355.     /* add in a contribution for the vertical light. The normalisation    */
  356.     /* factor is applied later                                            */
  357.     /* ---------------------------------------------------------------- */
  358.  
  359.     dshade = vstrength;
  360.   
  361.     if( p >= shadow ) {
  362.  
  363.         /* ------------------------------------------------------------ */
  364.         /* add in contribution from the main light source                */
  365.         /* ------------------------------------------------------------ */
  366.  
  367.         dshade += lstrength * ( delta_x * x_fact + delta_y * y_fact + sin_phi );
  368.     }
  369.  
  370.     /* ---------------------------------------------------------------- */
  371.     /* divide by the normalisation factor (the same for both light        */
  372.     /* sources)                                                            */
  373.     /* ---------------------------------------------------------------- */
  374.  
  375.     dshade /= norm;
  376.  
  377.     /* ---------------------------------------------------------------- */
  378.     /* calculate shading                                                */
  379.     /*                                                                    */
  380.     /* dshade should be in the range 0.0 -> 1.0                            */
  381.     /* if the light intensities add to 1.0                                */
  382.     /* now convert to an integer                                        */
  383.     /* ---------------------------------------------------------------- */
  384.  
  385.     shade = dshade * band_size;
  386.     if ( shade > band_size - 1 ) {
  387.         shade = band_size - 1;
  388.     }
  389.  
  390.     /* ---------------------------------------------------------------- */
  391.     /* if shade is negative then point is really in deep shadow            */
  392.     /* ---------------------------------------------------------------- */
  393.  
  394.     if( shade < 0 ) {
  395.         shade = 0;
  396.     }
  397.  
  398.     result += shade;
  399.     if( result >= n_col || result < 0 ) {
  400.         Printf( "INTERNAL ERROR colour out of range %ld\n", result );
  401.         exit( 1 );
  402.     }
  403.     return result;
  404. }
  405.  
  406.  
  407. /* -------------------------------------------------------------------- */
  408. /* This routine returns a plan view of the surface                        */
  409. /* -------------------------------------------------------------------- */
  410.  
  411. Col *makemap( Height *a, Height *b, Height *shadow )
  412. {
  413.     Col    *res;
  414.     int    i;
  415.  
  416.     res = (Col *) malloc( width * sizeof( Col ) );
  417.     if ( res == NULL ) {
  418.         PutStr( "malloc failed for colour strip\n" );
  419.         exit( 1 );
  420.     }
  421.     res[0] = BLACK;
  422.     for( i = 1; i < width; i++ ) {
  423.         res[i] = get_col( b[i], a[i], b[i-1], shadow[i] );
  424.     }
  425.     return res;
  426. }
  427.  
  428. /* -------------------------------------------------------------------- */
  429. /* this routine returns a perspective view of the surface                */
  430. /* -------------------------------------------------------------------- */
  431.   
  432. Col *camera( Height *a, Height *b, Height *shadow )
  433. {
  434.     int    i, coord, last;
  435.     Col    *res, col;
  436.  
  437.     res = (Col *) malloc( height * sizeof( Col ) );
  438.     if( res == NULL ) {
  439.         PutStr( "malloc failed for picture strip\n" );
  440.         exit( 1 );
  441.     }
  442.  
  443.     /* ---------------------------------------------------------------- */
  444.     /* optimised painters algorithm                                        */
  445.     /*                                                                    */
  446.     /* scan from front to back, we can avoid calculating the            */
  447.     /* colour if the point is not visable.                                */
  448.     /* ---------------------------------------------------------------- */
  449.  
  450.     for( i = last = 0 ; i < width && last < height; i++ ) {
  451.         if( a[i] < sealevel ) {
  452.             a[i] = sealevel;
  453.         }
  454.         coord = 1 + project( i, a[i] );
  455.         if ( coord > last ) {
  456.  
  457.             /* -------------------------------------------------------- */
  458.             /* get the colour of this point, the front strip should be    */
  459.             /* black                                                    */
  460.             /* -------------------------------------------------------- */
  461.  
  462.             if ( i == 0 ) {
  463.                 col = BLACK;
  464.             }
  465.             else {
  466.                 col = get_col( b[i], a[i], b[i-1], shadow[i] );
  467.             }
  468.             if ( coord > height ) {
  469.                 coord = height;
  470.             }
  471.             for ( ; last<coord; last++ ) {
  472.                 res[last] = col;
  473.             }
  474.         }
  475.     }
  476.     for ( ; last < height; last++ ) {
  477.         res[last] = SKY;
  478.     }
  479.     return res;
  480. }
  481.  
  482. /* -------------------------------------------------------------------- */
  483. /* this routine returns a perspective view of the surface with            */
  484. /* reflections in the water                                                */
  485. /* -------------------------------------------------------------------- */
  486.  
  487. Col *mirror( Height *a, Height *b, Height *shadow )
  488. {
  489.     Col        *res, *map;
  490.     Col        last_col;
  491.     int        i, j, top, bottom, coord;
  492.     int        last_top, last_bottom;
  493.     Height pivot;
  494.  
  495.     res = (Col *) malloc( height * sizeof( Col ) );
  496.     if( res == NULL ) {
  497.         PutStr( "malloc failed for picture strip\n" );
  498.         exit( 1 );
  499.     }
  500.     last_col    = SKY;
  501.     last_top    = height - 1;
  502.     last_bottom    = 0;
  503.  
  504.     /* ---------------------------------------------------------------- */
  505.     /* many of the optimisation in the camera routine are hard to        */
  506.     /* implement in this case so we revert to the simple painters        */
  507.     /* algorithm modified to produce reflections scan from back to        */
  508.     /* front drawing strips between the projected position of height    */
  509.     /* and -height. for water stipple the colour so the reflection is    */
  510.     /* still visable                                                    */
  511.     /* ---------------------------------------------------------------- */
  512.  
  513.     map        = makemap( a, b, shadow );
  514.     pivot    = 2.0 * sealevel;
  515.     for ( i = width - 1; i > 0; i-- ) {
  516.         if ( map[i] < BAND_BASE ) {
  517.  
  518.             /* -------------------------------------------------------- */
  519.             /* stipple water values                                        */
  520.             /* -------------------------------------------------------- */
  521.  
  522.             for( j = last_bottom; j <= last_top; j++ ) {
  523.                 res[j] = last_col;
  524.             }
  525.             last_col = map[i];
  526.  
  527.             /* -------------------------------------------------------- */
  528.             /* invalidate strip so last stip does not exist                */
  529.             /* -------------------------------------------------------- */
  530.  
  531.             last_bottom = height;
  532.             last_top    = -1;
  533.  
  534.             /* -------------------------------------------------------- */
  535.             /* fill in water values                                        */
  536.             /* -------------------------------------------------------- */
  537.  
  538.             coord = 1 + project( i, sealevel );
  539.             for ( j = 0; j < coord; j++ ) {
  540.  
  541.                 /* ---------------------------------------------------- */
  542.                 /* do not print on every other point if the current        */
  543.                 /* value is a land value                                */
  544.                 /* ---------------------------------------------------- */
  545.  
  546.                 if ( ( j + base ) % 2 || res[j] < BAND_BASE ) {
  547.                     res[j] = map[i];
  548.                 }
  549.             }
  550.  
  551.             /* -------------------------------------------------------- */
  552.             /* skip any adjacent bits of water with the same colour        */
  553.             /* -------------------------------------------------------- */
  554.  
  555.             while ( map[i] == last_col ) {
  556.                 i--;
  557.             }
  558.             i++;    // the end of the for loop will decrement as well
  559.         }
  560.         else {
  561.  
  562.             /* -------------------------------------------------------- */
  563.             /* draw land values                                            */
  564.             /* -------------------------------------------------------- */
  565.  
  566.             top        = project( i, a[i] );
  567.             bottom    = project( i, pivot - a[i] );
  568.             if( last_col == map[i] ) {
  569.                 if( top > last_top ) {
  570.                     last_top = top;
  571.                 }
  572.                 if( bottom < last_bottom ) {
  573.                     last_bottom = bottom;
  574.                 }
  575.             }
  576.             else {
  577.                 if ( top < last_top ) {
  578.                     for ( j = top + 1; j <= last_top; j++ ) {
  579.                         res[j] = last_col;
  580.                     }
  581.                 }
  582.                 if ( bottom > last_bottom ) {
  583.                     for ( j = last_bottom; j < bottom; j++ ) {
  584.                         res[j] = last_col;
  585.                     }
  586.                 }
  587.                 last_top    = top;
  588.                 last_bottom    = bottom;
  589.                 last_col    = map[i];
  590.             }
  591.         }
  592.     }
  593.  
  594.     /* ---------------------------------------------------------------- */
  595.     /* draw in front face                                                */
  596.     /* ---------------------------------------------------------------- */
  597.  
  598.     for ( j = last_bottom; j <= last_top; j++ ) {
  599.         res[j] = last_col;
  600.     }
  601.     if( a[0] < sealevel ) {
  602.         coord = 1 + project( 0, sealevel );
  603.     }
  604.     else {
  605.         coord = 1 + project( 0, a[0] );
  606.     }
  607.     for( j = 0; j < coord; j++ ) {
  608.         res[j] = map[0];
  609.     }
  610.  
  611.     base = 1 - base;
  612.     free( map );
  613.     return res;
  614. }
  615.  
  616. /* -------------------------------------------------------------------- */
  617. /* project a point onto the screen position                                */
  618. /* -------------------------------------------------------------------- */
  619.  
  620. static int project( int x, Height y )
  621. {
  622.     int pos;
  623. #ifndef SLOPPY
  624.     double theta;
  625.  
  626.     theta    = atan( ( viewheight - y ) / ( x - viewpos ) ) - vangle;
  627.     pos        = height / 2 - focal * tan( theta );
  628. #else
  629.     double tan_theta;
  630.  
  631.     /* ---------------------------------------------------------------- */
  632.     /* nast approx to avoid trig functions                                */
  633.     /* ---------------------------------------------------------------- */
  634.  
  635.     tan_theta    = ( viewheight - y ) / ( x - viewpos ) - tan_vangle;
  636.     pos            = height / 2 - focal * tan_theta;
  637. #endif
  638.     if( pos > height - 1 ) {
  639.         pos = height - 1;
  640.     }
  641.     else if ( pos < 0 ) {
  642.         pos = 0;
  643.     }
  644.     return pos;
  645. }
  646.  
  647. /* -------------------------------------------------------------------- */
  648. /* Tidy up and free everything.                                            */
  649. /* -------------------------------------------------------------------- */
  650.  
  651. void finish_artist( void )
  652. {
  653.     free( a_strip );
  654.     free( b_strip );
  655.     free( shadow );
  656.     free_fold( top );
  657. }
  658.